﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace UtilZ.Dotnet.Ex.DataStruct
{
    /// <summary>
    /// 线程安全的两种类型的相互关联映射集合
    /// </summary>
    /// <typeparam name="T1">类型1</typeparam>
    /// <typeparam name="T2">类型2</typeparam>
    public class ConcurrentCorrelateMap<T1, T2> : IEnumerable<KeyValuePair<T1, T2>>
    {
        private readonly Dictionary<T1, T2> _dic;
        private readonly Dictionary<T2, T1> _reverseDic;
        /// <summary>
        /// 获取可用于同步对DictionaryEx的访问的对象。
        /// </summary>
        public readonly object SyncRoot = new object();

        /// <summary>
        /// 构造函数
        /// </summary>
        public ConcurrentCorrelateMap()
        {
            this._dic = new Dictionary<T1, T2>();
            this._reverseDic = new Dictionary<T2, T1>();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dic">初始化字典集合,要求字典中的key和value集合中的值皆不能重复</param>
        /// <exception cref="ArgumentNullException">如果dic为null将抛出异常</exception>
        public ConcurrentCorrelateMap(IDictionary<T1, T2> dic)
        {
            if (dic == null)
            {
                throw new ArgumentNullException(nameof(dic));
            }

            this._dic = new Dictionary<T1, T2>(dic);

            this._reverseDic = new Dictionary<T2, T1>();
            foreach (var kv in dic)
            {
                if (this._reverseDic.ContainsKey(kv.Value))
                {
                    throw new ArgumentException($"key:{kv.Key}对应的valu8e:{kv.Value}值重复");
                }

                this._reverseDic.Add(kv.Value, kv.Key);
            }
        }

        /// <summary>
        /// 添加关系项
        /// </summary>
        /// <param name="key">T1类型的key</param>
        /// <param name="value">T2类型的value</param>
        /// <exception cref="ArgumentNullException">key为null将抛出异常</exception>
        /// <exception cref="ArgumentException">value为null将抛出异常</exception>
        public void Add(T1 key, T2 value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }


            lock (this.SyncRoot)
            {
                if (this._dic.ContainsKey(key))
                {
                    throw new ArgumentException($"key:{key}已存在");
                }

                if (this._reverseDic.ContainsKey(value))
                {
                    throw new ArgumentException($"value:{value}已存在");
                }

                this._dic.Add(key, value);
                this._reverseDic.Add(value, key);
            }
        }

        /// <summary>
        /// 添加关系项
        /// </summary>
        /// <param name="key">T2类型的key</param>
        /// <param name="value">T1类型的value</param>
        /// <exception cref="ArgumentNullException">key为null将抛出异常</exception>
        /// <exception cref="ArgumentException">value为null将抛出异常</exception>
        public void Add(T2 key, T1 value)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            lock (this.SyncRoot)
            {
                if (this._reverseDic.ContainsKey(key))
                {
                    throw new ArgumentException($"key:{key}已存在");
                }

                if (this._dic.ContainsKey(value))
                {
                    throw new ArgumentException($"value:{value}已存在");
                }

                this._reverseDic.Add(key, value);
                this._dic.Add(value, key);
            }
        }

        /// <summary>
        /// 移除项
        /// </summary>
        /// <param name="key">T1类型的key</param>
        /// <exception cref="ArgumentNullException">key为null将抛出异常</exception>
        public void Remove(T1 key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            
            lock (this.SyncRoot)
            {
                T2 value;
                if (this._dic.TryGetValue(key, out value))
                {
                    this._dic.Remove(key);
                    this._reverseDic.Remove(value);
                }
            }
        }

        /// <summary>
        /// 移除项
        /// </summary>
        /// <param name="key">T2类型的key</param>
        /// <exception cref="ArgumentNullException">key为null将抛出异常</exception>
        public void Remove(T2 key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            lock (this.SyncRoot)
            {
                T1 value;
                if (this._reverseDic.TryGetValue(key, out value))
                {
                    this._reverseDic.Remove(key);
                    this._dic.Remove(value);
                }
            }
        }

        /// <summary>
        /// 清空映射集合
        /// </summary>
        public void Clear()
        {
            lock (this.SyncRoot)
            {
                this._reverseDic.Clear();
                this._dic.Clear();
            }
        }

        /// <summary>
        /// 根据索引获取或设置值
        /// </summary>
        /// <param name="key">T1类型的key</param>
        /// <returns>T2类型的value</returns>
        /// <exception cref="ArgumentNullException">key为null将抛出异常</exception>
        public T2 this[T1 key]
        {
            get
            {
                if (key == null)
                {
                    throw new ArgumentNullException(nameof(key));
                }

                lock (this.SyncRoot)
                {
                    return this._dic[key];
                }
            }
            set
            {
                if (key == null)
                {
                    throw new ArgumentNullException(nameof(key));
                }

                lock (this.SyncRoot)
                {
                    this._dic[key] = value;
                }
            }
        }

        /// <summary>
        /// 根据索引获取或设置值
        /// </summary>
        /// <param name="key">T2类型的key</param>
        /// <returns>T1类型的value</returns>
        /// <exception cref="ArgumentNullException">key为null将抛出异常</exception>
        public T1 this[T2 key]
        {
            get
            {
                if (key == null)
                {
                    throw new ArgumentNullException(nameof(key));
                }

                lock (this.SyncRoot)
                {
                    return this._reverseDic[key];
                }
            }
            set
            {
                if (key == null)
                {
                    throw new ArgumentNullException(nameof(key));
                }

                lock (this.SyncRoot)
                {
                    this._reverseDic[key] = value;
                }
            }
        }

        /// <summary>
        /// 尝试获取T1类型key映射的T2类型的value.获取成功返回true,获取失败返回false
        /// </summary>
        /// <param name="key">T1类型的key</param>
        /// <param name="value">T2类型的value</param>
        /// <returns>获取成功返回true,获取失败返回false</returns>
        public bool TryGetValue(T1 key, out T2 value)
        {
            lock (this.SyncRoot)
            {
                return this._dic.TryGetValue(key, out value);
            }
        }

        /// <summary>
        /// 尝试获取T2类型key映射的T1类型的value.获取成功返回true,获取失败返回false
        /// </summary>
        /// <param name="key">T2类型的key</param>
        /// <param name="value">T1类型的value</param>
        /// <returns>获取成功返回true,获取失败返回false</returns>
        public bool TryGetValue(T2 key, out T1 value)
        {
            lock (this.SyncRoot)
            {
                return this._reverseDic.TryGetValue(key, out value);
            }
        }

        /// <summary>
        /// 获取T1类型元素集合
        /// </summary>
        public IReadOnlyCollection<T1> T1Collection
        {
            get
            {
                lock (this.SyncRoot)
                {
                    return this._dic.Keys;
                }
            }
        }

        /// <summary>
        /// 获取T2类型元素集合
        /// </summary>
        public IReadOnlyCollection<T2> T2Collection
        {
            get
            {
                lock (this.SyncRoot)
                {
                    return this._dic.Values;
                }
            }
        }


        /// <summary>
        /// IEnumerable接口实现
        /// </summary>
        /// <returns></returns>
        public IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
        {
            lock (this.SyncRoot)
            {
                return this._dic.GetEnumerator();
            }
        }

        /// <summary>
        /// IEnumerable
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}
